package com.marvelution.samples.springmetadataattributes.attributes;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;

import org.springframework.aop.support.AopUtils;
import org.springframework.metadata.Attributes;
import org.springframework.util.Assert;

/**
 * The {@link SampleAttribute} Source class. This class is used to find the
 * {@link SampleAttribute} for a Method and Class combination
 * 
 * @author mark.rekveld
 * 
 */
public class SampleAttributeSource {

	/**
	 * The Spring Framework's Attribute implementation object
	 */
	private Attributes attributes;

	/**
	 * Getter for {@link #attributes}
	 * 
	 * @return
	 */
	public Attributes getAttributes() {
		Assert.notNull(attributes, "'attributes' is null");
		return attributes;
	}

	/**
	 * Setter for {@link #attributes}
	 * 
	 * @param attributes
	 */
	public void setAttributes(Attributes attributes) {
		this.attributes = attributes;
	}

	/**
	 * Method to obtain the {@link SampleAttribute} for the method and class
	 * specified
	 * 
	 * @param method
	 *            the {@link Method} object
	 * @param targetClass
	 *            the {@link Class} object
	 * @return the {@link SampleAttribute} if the Method or Class has a
	 *         {@link SampleAttribute} otherwise <code>null</code>
	 */
	public SampleAttribute getSampleAttribute(Method method, Class targetClass) {
		// Get the most specific method of the method specified
		Method specificMethod = AopUtils.getMostSpecificMethod(method,
				targetClass);
		// Find the SampleAttribute for the specificMethod and return it if it
		// is not null
		SampleAttribute attr = findSampleAttribute(getAttributes()
				.getAttributes(specificMethod));
		if (attr != null) {
			return attr;
		}
		// Still here? then the specificMethod doesn't hold a SampleAttribute,
		// try to get it from the Class
		attr = findSampleAttribute(getAttributes().getAttributes(
				specificMethod.getDeclaringClass()));
		if (attr != null) {
			return attr;
		}
		// Still here? Then try to get if from the original Method and Class
		// objects
		if (specificMethod != method) {
			attr = findSampleAttribute(getAttributes().getAttributes(method));
			if (attr != null) {
				return attr;
			}
			attr = findSampleAttribute(getAttributes().getAttributes(
					method.getDeclaringClass()));
			if (attr != null) {
				return attr;
			}
		}
		// Still here? Then this Method Class combination doesn't hold a
		// SampleAttribute
		return null;
	}

	/**
	 * Method to find the {@link SampleAttribute} from the {@link Collection}
	 * given
	 * 
	 * @param collection
	 *            the {@link Collection} of Attributes
	 * @return the {@link SampleAttribute} if in the {@link Collection}
	 *         otherwise <code>null</code>
	 */
	private SampleAttribute findSampleAttribute(Collection collection) {
		for (Iterator iter = collection.iterator(); iter.hasNext();) {
			Object attr = (Object) iter.next();
			if (attr instanceof SampleAttribute) {
				return (SampleAttribute) attr;
			}
		}
		return null;
	}
}
